home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / url.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-10  |  10.5 KB  |  454 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. /* Author: Josh MacDonald. */
  20.  
  21. #include "config.h"
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <sys/param.h>
  26. #include <sys/wait.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <errno.h>
  30.  
  31. #ifdef __EMX__
  32. #include <process.h>
  33. #endif
  34.  
  35. #include <libgimp/gimp.h>
  36.  
  37. #include "libgimp/stdplugins-intl.h"
  38.  
  39.  
  40. #define TIMEOUT "300"
  41. #define BUFSIZE 1024
  42.  
  43. static void   query (void);
  44. static void   run   (gchar      *name,
  45.              gint        nparams,
  46.              GimpParam  *param,
  47.              gint       *nreturn_vals,
  48.              GimpParam **return_vals);
  49.  
  50. static gint32   load_image (gchar             *filename,
  51.                 GimpRunModeType    run_mode,
  52.                 GimpPDBStatusType *status /* return value */);
  53.  
  54. GimpPlugInInfo PLUG_IN_INFO =
  55. {
  56.   NULL,  /* init_proc  */
  57.   NULL,  /* quit_proc  */
  58.   query, /* query_proc */
  59.   run,   /* run_proc   */
  60. };
  61.  
  62. MAIN ()
  63.  
  64. static void
  65. query (void)
  66. {
  67.   static GimpParamDef load_args[] =
  68.   {
  69.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  70.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  71.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  72.   };
  73.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  74.  
  75.   static GimpParamDef load_return_vals[] =
  76.   {
  77.     { GIMP_PDB_IMAGE, "image", "Output image" }
  78.   };
  79.   static gint nload_return_vals = (sizeof (load_return_vals) /
  80.                    sizeof (load_return_vals[0]));
  81.  
  82.   gimp_install_procedure ("file_url_load",
  83.                           "loads files given a URL",
  84.                           "You need to have GNU Wget installed.",
  85.                           "Spencer Kimball & Peter Mattis",
  86.                           "Spencer Kimball & Peter Mattis",
  87.                           "1995-1997",
  88.                           "<Load>/URL",
  89.               NULL,
  90.                           GIMP_PLUGIN,
  91.                           nload_args, nload_return_vals,
  92.                           load_args, load_return_vals);
  93.  
  94.   gimp_register_load_handler ("file_url_load",
  95.                   "",
  96.                   "http:,ftp:");
  97. }
  98.  
  99. static void
  100. run (gchar      *name,
  101.      gint        nparams,
  102.      GimpParam  *param,
  103.      gint       *nreturn_vals,
  104.      GimpParam **return_vals)
  105. {
  106.   static GimpParam  values[2];
  107.   GimpRunModeType   run_mode;
  108.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  109.   gint32            image_ID;
  110.  
  111.   run_mode = param[0].data.d_int32;
  112.  
  113.   *nreturn_vals = 1;
  114.   *return_vals  = values;
  115.   values[0].type          = GIMP_PDB_STATUS;
  116.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  117.  
  118.   if (strcmp (name, "file_url_load") == 0)
  119.     {
  120.       image_ID = load_image (param[2].data.d_string,
  121.                  run_mode,
  122.                  &status);
  123.  
  124.       if (image_ID != -1 &&
  125.       status == GIMP_PDB_SUCCESS)
  126.     {
  127.       *nreturn_vals = 2;
  128.       values[1].type         = GIMP_PDB_IMAGE;
  129.       values[1].data.d_image = image_ID;
  130.     }
  131.     }
  132.   else
  133.     {
  134.       status = GIMP_PDB_CALLING_ERROR;
  135.     }
  136.  
  137.   values[0].data.d_status = status;
  138. }
  139.  
  140. static gint32
  141. load_image (gchar             *filename,
  142.         GimpRunModeType    run_mode,
  143.         GimpPDBStatusType *status)
  144. {
  145.   gint32  image_ID;
  146.   gchar  *ext = strrchr (filename, '.');
  147.   gchar  *tmpname;
  148.   gint    pid;
  149.   gint    wpid;
  150.   gint    process_status;
  151.   gint    p[2];
  152.  
  153.   if (!ext || ext[1] == 0 || strchr(ext, '/'))
  154.     {
  155.       g_message ("url: can't open URL without an extension");
  156.       *status = GIMP_PDB_CALLING_ERROR;
  157.       return -1;
  158.     }
  159.  
  160.   tmpname = gimp_temp_name (ext + 1);
  161.  
  162. #ifndef __EMX__
  163.   if (pipe (p) != 0)
  164.     {
  165.       g_message ("url: pipe() failed: %s", g_strerror (errno));
  166.       g_free (tmpname);
  167.       *status = GIMP_PDB_EXECUTION_ERROR;
  168.       return -1;
  169.     }
  170.  
  171.   if ((pid = fork()) < 0)
  172.     {
  173.       g_message ("url: fork() failed: %s", g_strerror (errno));
  174.       g_free (tmpname);
  175.       *status = GIMP_PDB_EXECUTION_ERROR;
  176.       return -1;
  177.     }
  178.   else if (pid == 0)
  179.     {
  180.       close (p[0]);
  181.       close (2);
  182.       dup (p[1]);
  183.       close (p[1]);
  184.  
  185. #ifdef HAVE_PUTENV
  186.       /* produce deterministic output */
  187.       putenv ("LANGUAGE=C");
  188.       putenv ("LC_ALL=C");
  189.       putenv ("LANG=C");
  190. #endif
  191.  
  192.       execlp ("wget", "wget", "-T", TIMEOUT, filename, "-O", tmpname, NULL);
  193.       g_message ("url: exec() failed: wget: %s", g_strerror (errno));
  194.       g_free (tmpname);
  195.       _exit (127);
  196.     }
  197.   else
  198.     {
  199.       if (run_mode == GIMP_RUN_NONINTERACTIVE)
  200.     {
  201.       wpid = waitpid (pid, &process_status, 0);
  202.  
  203.       if ((wpid < 0)
  204.           || !WIFEXITED (process_status)
  205.           || (WEXITSTATUS (process_status) != 0))
  206.         {
  207.           g_message ("url: wget exited abnormally on URL %s", filename);
  208.           g_free (tmpname);
  209.           *status = GIMP_PDB_EXECUTION_ERROR;
  210.           return -1;
  211.         }
  212.     }
  213.       else
  214.     {
  215.       FILE     *input;
  216.       gchar     buf[BUFSIZE];
  217.       gboolean  seen_resolve = FALSE;
  218.       gboolean  connected = FALSE;
  219.       gboolean  file_found = FALSE;
  220.       gchar     sizestr[32];
  221.       gint      size = 0;
  222.       gchar    *message;
  223.       gint      i, j;
  224.       gchar     dot;
  225.       gint      kilobytes = 0;
  226.       gboolean  finished = FALSE;
  227.  
  228.       gboolean  debug = FALSE;
  229.  
  230. #define DEBUG(x) if (debug) fprintf (stderr, (x))
  231.  
  232.       close (p[1]);
  233.  
  234.       input = fdopen (p[0], "r");
  235.  
  236.       /*  hardcoded and not-really-foolproof scanning of wget putput  */
  237.  
  238.       if (fgets (buf, BUFSIZE, input) == NULL)
  239.         {
  240.           /*  no message here because failing on the first line means
  241.            *  that wget was not found
  242.            */
  243.           g_free (tmpname);
  244.           *status = GIMP_PDB_EXECUTION_ERROR;
  245.           return -1;
  246.         }
  247.  
  248.       DEBUG (buf);
  249.  
  250.       /*  The second line is the local copy of the file  */
  251.       if (fgets (buf, BUFSIZE, input) == NULL)
  252.         {
  253.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  254.           g_free (tmpname);
  255.           *status = GIMP_PDB_EXECUTION_ERROR;
  256.           return -1;
  257.         }
  258.  
  259.       DEBUG (buf);
  260.  
  261.       /*  The third line is "Connecting to..."  */
  262.       gimp_progress_init ("Connecting to server... "
  263.                   "(timeout is "TIMEOUT" seconds)");
  264.  
  265. read_connect:
  266.       if (fgets (buf, BUFSIZE, input) == NULL)
  267.         {
  268.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  269.           g_free (tmpname);
  270.           *status = GIMP_PDB_EXECUTION_ERROR;
  271.           return -1;
  272.         }
  273.       else if (strstr (buf, "connected"))
  274.         {
  275.           connected = TRUE;
  276.         }
  277.       /* newer wgets have a "Resolving foo" line, so eat it */
  278.       else if (!seen_resolve && strstr (buf, "Resolving"))
  279.         {
  280.           seen_resolve = TRUE;
  281.           goto read_connect;
  282.         }
  283.  
  284.       DEBUG (buf);
  285.  
  286.       /*  The fourth line is either the network request or an error  */
  287.       gimp_progress_init ("Opening URL... "
  288.                   "(timeout is "TIMEOUT" seconds)");
  289.  
  290.       if (fgets (buf, BUFSIZE, input) == NULL)
  291.         {
  292.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  293.           g_free (tmpname);
  294.           *status = GIMP_PDB_EXECUTION_ERROR;
  295.           return -1;
  296.         }
  297.       else if (! connected)
  298.         {
  299.           g_message ("url: a network error occured: %s", buf);
  300.  
  301.           DEBUG (buf);
  302.  
  303.           g_free (tmpname);
  304.           *status = GIMP_PDB_EXECUTION_ERROR;
  305.           return -1;
  306.         }
  307.  
  308.       DEBUG (buf);
  309.  
  310.       /*  The fifth line is either the length of the file or an error  */
  311.       if (fgets (buf, BUFSIZE, input) == NULL)
  312.         {
  313.           g_message ("url: wget exited abnormally on URL\n%s", filename);
  314.           g_free (tmpname);
  315.           *status = GIMP_PDB_EXECUTION_ERROR;
  316.           return -1;
  317.         }
  318.       else if (strstr (buf, "Length"))
  319.         {
  320.           file_found = TRUE;
  321.         }
  322.       else
  323.         {
  324.           g_message ("url: a network error occured: %s", buf);
  325.  
  326.           DEBUG (buf);
  327.  
  328.           g_free (tmpname);
  329.           *status = GIMP_PDB_EXECUTION_ERROR;
  330.           return -1;
  331.         }
  332.  
  333.       DEBUG (buf);
  334.  
  335.       if (sscanf (buf, "Length: %31s", sizestr) != 1)
  336.         {
  337.           g_message ("url: could not parse wget's file length message");
  338.           g_free (tmpname);
  339.           *status = GIMP_PDB_EXECUTION_ERROR;
  340.           return -1;
  341.         }
  342.  
  343.       /*  strip away commas  */
  344.       for (i = 0, j = 0; i < sizeof (sizestr); i++, j++)
  345.         {
  346.           if (sizestr[i] == ',')
  347.         i++;
  348.  
  349.           sizestr[j] = sizestr[i];
  350.  
  351.           if (sizestr[j] == '\0')
  352.         break;
  353.         }
  354.  
  355.       size = atoi (sizestr);
  356.  
  357.       /*  Start the actual download...  */
  358.       message = g_strdup_printf ("Downloading %d bytes of image data... "
  359.                      "(timeout is "TIMEOUT" seconds)", size);
  360.       gimp_progress_init (message);
  361.       g_free (message);
  362.  
  363.       /*  Switch to byte parsing wget's output...  */
  364.  
  365.       while (1)
  366.         {
  367.           dot = fgetc (input);
  368.  
  369.           if (feof (input))
  370.         break;
  371.  
  372.           if (debug)
  373.         {
  374.           fputc (dot, stderr);
  375.           fflush (stderr);
  376.         }
  377.  
  378.           if (dot == '.')  /* one kilobyte */
  379.         {
  380.           kilobytes++;
  381.           gimp_progress_update ((gdouble) (kilobytes * 1024) /
  382.                     (gdouble) size);
  383.         }
  384.           else if (dot == ':')  /* the time string contains a ':' */
  385.         {
  386.           fgets (buf, BUFSIZE, input);
  387.  
  388.           DEBUG (buf);
  389.  
  390.           if (! strstr (buf, "error"))
  391.             {
  392.               finished = TRUE;
  393.               gimp_progress_update (1.0);
  394.             }
  395.  
  396.           break;
  397.         }
  398.         }
  399.  
  400.       if (! finished)
  401.         {
  402.           g_message ("url: wget exited before finishing downloading URL\n%s",
  403.              filename);
  404.           unlink (tmpname);
  405.           g_free (tmpname);
  406.           *status = GIMP_PDB_EXECUTION_ERROR;
  407.           return -1;
  408.         }
  409.     }
  410.     }
  411. #else /* __EMX__ */
  412.   {
  413.     pid = spawnlp (P_NOWAIT,
  414.            "wget",
  415.            "wget", "-T", TIMEOUT, filename, "-O", tmpname, NULL);
  416.  
  417.     if (pid == -1)
  418.       {
  419.     g_message ("url: spawn failed: %s", g_strerror (errno));
  420.     g_free (tmpname);
  421.     *status = GIMP_PDB_EXECUTION_ERROR;
  422.     return -1;
  423.       }
  424.  
  425.     wpid = waitpid (pid, &process_status, 0);
  426.  
  427.     if ((wpid < 0)
  428.     || !WIFEXITED (process_status)
  429.     || (WEXITSTATUS (process_status) != 0))
  430.       {
  431.     g_message ("url: wget exited abnormally on URL %s", filename);
  432.     g_free (tmpname);
  433.     *status = GIMP_PDB_EXECUTION_ERROR;
  434.     return -1;
  435.       }
  436.   }
  437. #endif
  438.  
  439.   image_ID = gimp_file_load (GIMP_RUN_INTERACTIVE, tmpname, tmpname);
  440.  
  441.   unlink (tmpname);
  442.   g_free (tmpname);
  443.  
  444.   if (image_ID != -1)
  445.     {
  446.       *status = GIMP_PDB_SUCCESS;
  447.       gimp_image_set_filename (image_ID, filename);
  448.     }
  449.   else
  450.     *status = GIMP_PDB_EXECUTION_ERROR;
  451.  
  452.   return image_ID;
  453. }
  454.